package com.ruoyi.net.service.impl;

import com.ruoyi.common.constant.ElementConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.GraphUtil;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.GlobalCounter;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.net.domain.*;
import com.ruoyi.net.mapper.*;
import com.ruoyi.net.service.IBusiMtnChannelService;
import com.ruoyi.net.service.INetGroupService;
import com.ruoyi.net.utils.autoIncrement.GlobalIncrementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

import static com.ruoyi.net.service.impl.BusiMplstpServiceImpl.findTwoShortestArrays;

/**
 * 业务-MTN Channel配置Service业务层处理
 *
 * @author tony
 * @date 2024-12-08
 */
@Service
public class BusiMtnChannelServiceImpl implements IBusiMtnChannelService {
    @Autowired
    INetGroupService netGroupService;
    @Autowired
    BusiMtnChannelRouteGraphMapper busiMtnChannelRouteGraphMapper;
    @Autowired
    BusiMtnChannelRouteElementsMapper busiMtnChannelRouteElementsMapper;
    @Autowired
    ElementBusiMtnChannelGrainMapper busiMtnChannelGrainMapper;
    @Autowired
    ElementPortMtnEvthMapper elementPortMtnEvthMapper;
    @Autowired
    ElementBusiMtnChannelVethMapper elementBusiMtnChannelVethMapper;
    @Autowired
    ElementBusiMtnChannelGrainMapper elementBusiMtnChannelGrainMapper;
    @Autowired
    BusiMtnChannelRouteTableMapper busiMtnChannelRouteTableMapper;
    @Autowired
    BusiMtnChannelCrossMapper busiMtnChannelCrossMapper;
    @Autowired
    ElementPortModeMapper elementPortModeMapper;
    @Autowired
    BusiMtnChannelSubclientMapper busiMtnChannelSubclientMapper;
    @Autowired
    ElementBusiMtnclientFgMapper elementBusiMtnclientFgMapper;
    @Autowired
    GlobalIncrementService globalIncrementService;
    @Autowired
    BusiElementStatusMapper busiElementStatusMapper;
    @Autowired
    BusiMtnChannelConstraintMapper busiMtnChannelConstraintMapper;
    @Autowired
    private BusiMtnChannelMapper busiMtnChannelMapper;
    @Autowired
    private BusiMtnChannelRouteMapper busiMtnChannelRouteMapper;
    @Autowired
    private ElementBusiMtnChannelOtherMapper elementBusiMtnChannelOtherMapper;
    @Autowired
    private ElementBusiMtnChannelProtectMapper elementBusiMtnChannelProtectMapper;
    @Autowired
    private ElementBusiMtnChannelOamMapper elementBusiMtnChannelOamMapper;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private NetElementLinkMapper netElementLinkMapper;
    private boolean hasFilterFlag = false;

    /**
     * 查询业务-MTN Channel配置
     *
     * @param id 业务-MTN Channel配置主键
     * @return 业务-MTN Channel配置
     */
    @Override
    public BusiMtnChannel selectBusiMtnChannelById(String id) {
        return busiMtnChannelMapper.selectBusiMtnChannelById(id);
    }

    /**
     * 查询业务-MTN Channel配置列表
     *
     * @param busiMtnChannel 业务-MTN Channel配置
     * @return 业务-MTN Channel配置
     */
    @Override
    public List<BusiMtnChannelListVo> selectBusiMtnChannelList(BusiMtnChannel busiMtnChannel) {
        return busiMtnChannelMapper.selectBusiMtnChannelList(busiMtnChannel);
    }

    /**
     * 新增业务-MTN Channel配置
     *
     * @param busiMtnChannelVo 业务-MTN Channel配置
     * @return 结果
     */
    @Override
    public int insertBusiMtnChannel(BusiMtnChannelVo busiMtnChannelVo) {
        String uuid = IdUtils.simpleUUID();
        if (StringUtils.isEmpty(busiMtnChannelVo.getId())) {
            busiMtnChannelVo.setId(uuid);
        }
        //  判断表中是否已存在该数据，存在则更新，否则新增
        if (busiMtnChannelMapper.selectBusiMtnChannelById(busiMtnChannelVo.getId()) != null) {
            //更新主表
            int i = busiMtnChannelMapper.updateBusiMtnChannel(busiMtnChannelVo);
            //先删除再插入
            initUpdateBusiMtnChannelAttachInfo(busiMtnChannelVo);
            updateBusiMtnChannelRouteGraph(busiMtnChannelVo);

            initInsertBusiMtnChannelAttachInfo(busiMtnChannelVo);
            //先删除再插入
//            insertBusiMtnChannelRouteGraph(busiMtnChannelVo);

            //删除路径附表，重新绑定新数据
            busiMtnChannelRouteMapper.deleteBusiMtnChannelRouteByMtnChannelId(busiMtnChannelVo.getId());
            if (!CollectionUtils.isEmpty(busiMtnChannelVo.getBusiMtnChannelRouteList())) {
                for (BusiMtnChannelRoute busiMtnChannelRoute : busiMtnChannelVo.getBusiMtnChannelRouteList()) {
                    busiMtnChannelRoute.setId(IdUtils.simpleUUID());
                    busiMtnChannelRoute.setMtnChannelId(busiMtnChannelVo.getId());
                    busiMtnChannelRoute.setCreateBy(SecurityUtils.getUsername());
                    busiMtnChannelRoute.setCreateTime(DateUtils.getNowDate());
                    busiMtnChannelRoute.setUpdateBy(SecurityUtils.getUsername());
                    busiMtnChannelRoute.setUpdateTime(DateUtils.getNowDate());
                }
                busiMtnChannelRouteMapper.batchInsertBusiMtnChannelRoute(busiMtnChannelVo.getBusiMtnChannelRouteList());
            }
            return i;
        } else {
            //初始化新增MTN-Channel业务主表的各附属信息
            initInsertBusiMtnChannelAttachInfo(busiMtnChannelVo);

            if (!CollectionUtils.isEmpty(busiMtnChannelVo.getBusiMtnChannelRouteList())) {
                for (BusiMtnChannelRoute busiMtnChannelRoute : busiMtnChannelVo.getBusiMtnChannelRouteList()) {
                    busiMtnChannelRoute.setCreateBy(SecurityUtils.getUsername());
                    busiMtnChannelRoute.setCreateTime(DateUtils.getNowDate());
                    busiMtnChannelRoute.setUpdateBy(SecurityUtils.getUsername());
                    busiMtnChannelRoute.setUpdateTime(DateUtils.getNowDate());
                }
                //批量新增路由配置
                busiMtnChannelRouteMapper.batchInsertBusiMtnChannelRoute(busiMtnChannelVo.getBusiMtnChannelRouteList());
            }
            busiMtnChannelVo.setCreateBy(SecurityUtils.getUsername());
            busiMtnChannelVo.setCreateTime(DateUtils.getNowDate());
            busiMtnChannelVo.setUpdateBy(SecurityUtils.getUsername());
            busiMtnChannelVo.setUpdateTime(DateUtils.getNowDate());
            busiMtnChannelVo.setStatus(ElementConstants.STATUS_OFF);
            return busiMtnChannelMapper.insertBusiMtnChannel(busiMtnChannelVo);
        }
    }

    /**
     * 初始化更新业务MTNChannel路由
     */
    private void updateBusiMtnChannelRouteGraph(BusiMtnChannelVo busiMtnChannelVo) {
        busiMtnChannelRouteGraphMapper.deleteBusiMplstpRouteGraphByMtnChannelId(busiMtnChannelVo.getId());
        busiMtnChannelRouteElementsMapper.deleteBusiMplstpRouteElementsByMtnChannelId(busiMtnChannelVo.getId());
        busiMtnChannelRouteTableMapper.deleteBusiMtnChannelRouteTableByMtnChannelId(busiMtnChannelVo.getId());
        busiMtnChannelCrossMapper.deleteBusiMtnChannelCrossByMtnChannelId(busiMtnChannelVo.getId());
    }

    /**
     * 初始化更新业务MTNChannel附属信息
     *
     * @param busiMtnChannelVo
     */
    private void initUpdateBusiMtnChannelAttachInfo(BusiMtnChannelVo busiMtnChannelVo) {
        elementBusiMtnChannelOamMapper.deleteElementBusiMtnChannelOamByMtnChannelId(busiMtnChannelVo.getId());
        elementBusiMtnChannelOtherMapper.deleteElementBusiMtnChannelOtherByMtnChannelId(busiMtnChannelVo.getId());
        elementBusiMtnChannelProtectMapper.deleteElementBusiMtnChannelProtectByMtnChannelId(busiMtnChannelVo.getId());
        elementBusiMtnChannelGrainMapper.deleteElementBusiMtnChannelGrainByMtnChannelId(busiMtnChannelVo.getId());
        elementBusiMtnChannelVethMapper.deleteElementBusiMtnChannelVethByMtnChannelId(busiMtnChannelVo.getId());
        //删除subclient表
        busiMtnChannelSubclientMapper.deleteBusiMtnChannelSubclientByMtnChannelId(busiMtnChannelVo.getId());
        //删除fgClient表
        elementBusiMtnclientFgMapper.deleteElementBusiMtnclientFgByMtnChannelId(busiMtnChannelVo.getId());
        busiElementStatusMapper.deleteBusiElementStatusBySrtpId(busiMtnChannelVo.getId());

    }

    /**
     * 初始化业务MTN-Channel附属信息
     *
     * @param busiMtnChannelVo
     */
    @Transactional(rollbackFor = Exception.class)
    void initInsertBusiMtnChannelAttachInfo(BusiMtnChannelVo busiMtnChannelVo) {
        //不论类型 生成其他属性、路由图 、路由表、公共属性
        insertBusiMtnChannelCommon(busiMtnChannelVo);
        //业务类型如果是MTN Channel  1、默认生成VETH接口、其他属性 2、oam使能 生成oam 3、MTN1+1保护类型生成保护类型
        /*if ("MTN Channel".equals(busiMtnChannelVo.getMtnType()) ||
                "MTN FG-Channel".equals(busiMtnChannelVo.getMtnType())) {

            //生成VETH接口
            insertVethInfo(busiMtnChannelVo);
            //调用VETH接口模版数据并新增
            if ("MTN1+1保护".equals(busiMtnChannelVo.getProtectType()) && "1".equals(busiMtnChannelVo.getOamEnable())) {
                //调用保护属性模版数据并新增
                insertBusiMtnChannelProtect(busiMtnChannelVo);
                //oam数据生成4份
                //oam-工作路径-源网元
                insertBusiMtnChannelOam(busiMtnChannelVo, "1", busiMtnChannelVo.getStartElement());
                //oam-工作路径-宿网元
                insertBusiMtnChannelOam(busiMtnChannelVo, "1", busiMtnChannelVo.getEndElement());
                //oam-保护路径-源网元
                insertBusiMtnChannelOam(busiMtnChannelVo, "2", busiMtnChannelVo.getStartElement());
                //oam-保护路径-宿网元
                insertBusiMtnChannelOam(busiMtnChannelVo, "2", busiMtnChannelVo.getEndElement());



            } else if ("无保护".equals(busiMtnChannelVo.getProtectType()) && "1".equals(busiMtnChannelVo.getOamEnable())) {
                //oam数据生成2份 工作路径-源网元、工作路径-宿网元
                insertBusiMtnChannelOam(busiMtnChannelVo, "1", busiMtnChannelVo.getStartElement());
                insertBusiMtnChannelOam(busiMtnChannelVo, "1", busiMtnChannelVo.getEndElement());

            }
        //2.11  业务已经去掉该类型 ，代码废弃
        } else if ("MTN Channel服务层".equals(busiMtnChannelVo.getMtnType())) {
           //获取分析路由头尾端口信息
            BusiMtnChannelRouteGraph workRouteGraph = getAnalyseRouteInfo(busiMtnChannelVo.getId(), "1");
            BusiMtnChannelRouteGraph protectRouteGraph = getAnalyseRouteInfo(busiMtnChannelVo.getId(), "2");
            //生成细粒度业务盘保护组
            if ("MTN1+1保护".equals(busiMtnChannelVo.getProtectType()) && "1".equals(busiMtnChannelVo.getOamEnable())) {
                //调用保护属性模版数据并新增
                insertBusiMtnChannelProtect(busiMtnChannelVo);
                //oam数据生成4份
                //oam-工作路径-源网元
                insertBusiMtnChannelOam(busiMtnChannelVo, "1", busiMtnChannelVo.getStartElement());
                //oam-工作路径-宿网元
                insertBusiMtnChannelOam(busiMtnChannelVo, "1", busiMtnChannelVo.getEndElement());
                //oam-保护路径-源网元
                insertBusiMtnChannelOam(busiMtnChannelVo, "2", busiMtnChannelVo.getStartElement());
                //oam-保护路径-宿网元
                insertBusiMtnChannelOam(busiMtnChannelVo, "2", busiMtnChannelVo.getEndElement());
                //生成4份粒度业务盘保护组数据
                //工作路径-源网元-保护组
                insertBusiMtnChannelGrain(busiMtnChannelVo, "1", "1", workRouteGraph);
                //工作路径-宿网元-保护组
                insertBusiMtnChannelGrain(busiMtnChannelVo, "1", "2", workRouteGraph);
                //保护路径-源网元-保护组
                insertBusiMtnChannelGrain(busiMtnChannelVo, "2", "1", protectRouteGraph);
                //保护路径-宿网元-保护组
                insertBusiMtnChannelGrain(busiMtnChannelVo, "2", "2", protectRouteGraph);

            } else if ("无保护".equals(busiMtnChannelVo.getProtectType()) && "1".equals(busiMtnChannelVo.getOamEnable())) {
                //oam数据生成2份
                //oam-工作路径-源网元
                insertBusiMtnChannelOam(busiMtnChannelVo, "1", busiMtnChannelVo.getStartElement());
                //oam-工作路径-宿网元
                insertBusiMtnChannelOam(busiMtnChannelVo, "1", busiMtnChannelVo.getEndElement());

                //粒度业务盘保护组数据生成2份
                //工作路径-源网元-保护组
                insertBusiMtnChannelGrain(busiMtnChannelVo, "1", "1", workRouteGraph);
                //工作路径-宿网元-保护组
                insertBusiMtnChannelGrain(busiMtnChannelVo, "1", "2", workRouteGraph);
            }
        }*/
        //2.10业务调整：mtn channel 中只有mtn fg channel业务类型
        //生成VETH接口
        insertVethInfo(busiMtnChannelVo);
        //调用VETH接口模版数据并新增
        if ("MTN1+1保护".equals(busiMtnChannelVo.getProtectType()) && "enable".equals(busiMtnChannelVo.getOamEnable())) {
            //调用保护属性模版数据并新增
            insertBusiMtnChannelProtect(busiMtnChannelVo);
            //oam数据生成4份
            //oam-工作路径-源网元
            insertBusiMtnChannelOam(busiMtnChannelVo, "1", busiMtnChannelVo.getStartElement(), "1");
            //oam-工作路径-宿网元
            insertBusiMtnChannelOam(busiMtnChannelVo, "1", busiMtnChannelVo.getEndElement(), "2");
            //oam-保护路径-源网元
            insertBusiMtnChannelOam(busiMtnChannelVo, "2", busiMtnChannelVo.getStartElement(), "1");
            //oam-保护路径-宿网元
            insertBusiMtnChannelOam(busiMtnChannelVo, "2", busiMtnChannelVo.getEndElement(), "2");
        } else if ("无保护".equals(busiMtnChannelVo.getProtectType()) && "enable".equals(busiMtnChannelVo.getOamEnable())) {
            //oam数据生成2份 工作路径-源网元、工作路径-宿网元
            insertBusiMtnChannelOam(busiMtnChannelVo, "1", busiMtnChannelVo.getStartElement(), "1");
            insertBusiMtnChannelOam(busiMtnChannelVo, "1", busiMtnChannelVo.getEndElement(), "2");

        }
    }

    /**
     * 主表生成后，生成subclient数据  无保护1条  保护两条
     *
     * @param busiMtnChannelVo
     */
    private void insertBusiMtnChannelSubClient(String routeType, BusiMtnChannelVo busiMtnChannelVo, String fgClientId) {
        String fgNum = busiMtnChannelVo.getFgclientNum();
        BusiMtnChannelSubclient busiMtnChannelSubclient = new BusiMtnChannelSubclient();
        busiMtnChannelSubclient.setCreateBy(SecurityUtils.getUsername());
        busiMtnChannelSubclient.setCreateTime(DateUtils.getNowDate());
        busiMtnChannelSubclient.setId(IdUtils.simpleUUID());
        busiMtnChannelSubclient.setMtnChannelId(busiMtnChannelVo.getId());
        busiMtnChannelSubclient.setClientType(routeType);
        busiMtnChannelSubclient.setFgClientNum(String.valueOf(globalIncrementService.getNextClientNumIncrementNumber()));
//        busiMtnChannelSubclient.setTimeSlot(String.valueOf(globalIncrementService.getNextTimeSlotIncrementNumber()));//取路由中的值???工作保护是否可以保持一致
        busiMtnChannelSubclient.setTimeSlot(busiMtnChannelVo.getGlobalTimeSlot());//取路由中的值???工作保护是否可以保持一致

        busiMtnChannelSubclient.setDeviceMapperId(fgNum);//不明确是否唯一
        busiMtnChannelSubclient.setClientPortName("XGE/mtn-fgclient" + globalIncrementService.getNextClientNumIncrementNumber());
        busiMtnChannelSubclient.setPortName("XGE");
        busiMtnChannelSubclient.setFgClientId(fgClientId);
        busiMtnChannelSubclientMapper.insertBusiMtnChannelSubclient(busiMtnChannelSubclient);
    }

    /**
     * 插入单站VETH接口数据、业务关联veth表
     * a:一个业务生成两条（源、宿）单站veth表，只设置名称mtntunnel{d}
     * b:一个业务生成一条业务veth表数据，源、宿网元VETHid取单站veth主键
     * 源网元FgClientIds：工作时为fgclient主键   保护时两个 fgclient主键 逗号分割
     * 3.9修改 fg不区分有无保护  一个业务生成源宿各一条  过站两条
     *
     * @param busiMtnChannelVo
     */
    private void insertVethInfo(BusiMtnChannelVo busiMtnChannelVo) {
        int globalNum = GlobalCounter.getNextCounter();
        //取源、宿对应端口
        String mtnChannelId = busiMtnChannelVo.getId();
//        BusiMtnChannelRouteGraph analyseRouteInfo = getAnalyseRouteInfo(mtnChannelId, "1");
        ElementPortMtnEvth elementPortMtnEvth1 = new ElementPortMtnEvth();
        elementPortMtnEvth1.setId(IdUtils.simpleUUID());
        elementPortMtnEvth1.setMtnChannelId(mtnChannelId);
        elementPortMtnEvth1.setElementId(busiMtnChannelVo.getStartElement());
        elementPortMtnEvth1.setTerminalName("mtnveth" + globalIncrementService.getNextSingleVethIdIncrementNumber());//自动生成  同一网元下该值唯一
        elementPortMtnEvth1.setCreateBy(SecurityUtils.getUsername());
        elementPortMtnEvth1.setCreateTime(DateUtils.getNowDate());
        elementPortMtnEvth1.setUpdateTime(DateUtils.getNowDate());
        //生成源evth
        elementPortMtnEvthMapper.insertElementPortMtnEvth(elementPortMtnEvth1);

        ElementPortMtnEvth elementPortMtnEvth2 = new ElementPortMtnEvth();
        elementPortMtnEvth2.setId(IdUtils.simpleUUID());
        elementPortMtnEvth2.setMtnChannelId(mtnChannelId);
        //自动生成  同一网元下该值唯一
        elementPortMtnEvth2.setTerminalName("mtnveth" + globalIncrementService.getNextSingleVethIdIncrementNumber());
        elementPortMtnEvth2.setElementId(busiMtnChannelVo.getEndElement());
        elementPortMtnEvth2.setCreateBy(SecurityUtils.getUsername());
        elementPortMtnEvth2.setCreateTime(DateUtils.getNowDate());
        elementPortMtnEvth2.setUpdateTime(DateUtils.getNowDate());
        //生成宿evth
        elementPortMtnEvthMapper.insertElementPortMtnEvth(elementPortMtnEvth2);
        //生成业务veth关联表
        ElementBusiMtnChannelVeth elementBusiMtnChannelVeth = new ElementBusiMtnChannelVeth();
        elementBusiMtnChannelVeth.setStartElementVethId(elementPortMtnEvth1.getId());
        elementBusiMtnChannelVeth.setEndElementVethId(elementPortMtnEvth2.getId());
        elementBusiMtnChannelVeth.setId(IdUtils.simpleUUID());
        elementBusiMtnChannelVeth.setMtnChannelId(mtnChannelId);
        elementBusiMtnChannelVeth.setCreateBy(SecurityUtils.getUsername());
        elementBusiMtnChannelVeth.setCreateTime(DateUtils.getNowDate());
        elementBusiMtnChannelVeth.setUpdateBy(SecurityUtils.getUsername());
        elementBusiMtnChannelVeth.setUpdateTime(DateUtils.getNowDate());
        //这里取fgclient主键
        ElementBusiMtnclientFg busiMtnclientFg = new ElementBusiMtnclientFg();
        busiMtnclientFg.setMtnChannelId(mtnChannelId);

        /*if ("MTN1+1保护".equals(busiMtnChannelVo.getProtectType())) {
            busiMtnclientFg.setElementId(busiMtnChannelVo.getStartElement());
            List<ElementBusiMtnclientFg> startMtnclientFgs = elementBusiMtnclientFgMapper.selectElementBusiMtnclientFgList(busiMtnclientFg);
            busiMtnclientFg.setElementId(busiMtnChannelVo.getEndElement());
            List<ElementBusiMtnclientFg> endMtnclientFgs = elementBusiMtnclientFgMapper.selectElementBusiMtnclientFgList(busiMtnclientFg);
            elementBusiMtnChannelVeth.setStartFgclientIds(startMtnclientFgs.get(0).getId()+","+startMtnclientFgs.get(1).getId());
            elementBusiMtnChannelVeth.setEndFgclientIds(endMtnclientFgs.get(0).getId()+","+endMtnclientFgs.get(1).getId());
        }else{
            busiMtnclientFg.setRouteType("1");
            busiMtnclientFg.setElementId(busiMtnChannelVo.getStartElement());
            busiMtnclientFg.setDelFlag("2");//此时fg还未正式创建
            List<ElementBusiMtnclientFg> startMtnclientFgs = elementBusiMtnclientFgMapper.selectElementBusiMtnclientFgList(busiMtnclientFg);
            busiMtnclientFg.setElementId(busiMtnChannelVo.getEndElement());
            List<ElementBusiMtnclientFg> endMtnclientFgs = elementBusiMtnclientFgMapper.selectElementBusiMtnclientFgList(busiMtnclientFg);
            elementBusiMtnChannelVeth.setStartFgclientIds(startMtnclientFgs.get(0).getId());
            elementBusiMtnChannelVeth.setEndFgclientIds(endMtnclientFgs.get(0).getId());
        }*/
//        busiMtnclientFg.setRouteType("1");
        busiMtnclientFg.setElementId(busiMtnChannelVo.getStartElement());
        busiMtnclientFg.setDelFlag("2");//此时fg还未正式创建
        List<ElementBusiMtnclientFgVo> startMtnclientFgs = elementBusiMtnclientFgMapper.selectElementBusiMtnclientFgList(busiMtnclientFg);
        busiMtnclientFg.setElementId(busiMtnChannelVo.getEndElement());
        List<ElementBusiMtnclientFgVo> endMtnclientFgs = elementBusiMtnclientFgMapper.selectElementBusiMtnclientFgList(busiMtnclientFg);
        elementBusiMtnChannelVeth.setStartFgclientIds(startMtnclientFgs.get(0).getId());
        elementBusiMtnChannelVeth.setEndFgclientIds(endMtnclientFgs.get(0).getId());

        elementBusiMtnChannelVethMapper.insertElementBusiMtnChannelVeth(elementBusiMtnChannelVeth);
    }

    /**
     * 根据mtnChannel外键、routeType
     * 获取分析路由头尾端口信息
     */
    public BusiMtnChannelRouteGraph getAnalyseRouteInfo(String mtnChannelId, String routeType) {
        BusiMtnChannelRouteGraph busiMtnChannelRouteGraph = new BusiMtnChannelRouteGraph();
        busiMtnChannelRouteGraph.setMtnChannelId(mtnChannelId);
        busiMtnChannelRouteGraph.setRouteType(routeType);
        List<BusiMtnChannelRouteGraph> busiMtnChannelRouteGraphs = busiMtnChannelRouteGraphMapper.selectBusiMtnChannelRouteGraphList(busiMtnChannelRouteGraph);
        if (!CollectionUtils.isEmpty(busiMtnChannelRouteGraphs)) {
            int size = busiMtnChannelRouteGraphs.size();
            String startPortId = busiMtnChannelRouteGraphs.get(0).getStartPortId();
            String startPort = busiMtnChannelRouteGraphs.get(0).getStartPort();
            String endPortId = busiMtnChannelRouteGraphs.get(size - 1).getStartPortId();
            String endPort = busiMtnChannelRouteGraphs.get(size - 1).getStartPort();
            busiMtnChannelRouteGraph.setStartPortId(startPortId);
            busiMtnChannelRouteGraph.setEndPortId(endPortId);
            busiMtnChannelRouteGraph.setStartPort(startPort);
            busiMtnChannelRouteGraph.setEndPort(endPort);
            busiMtnChannelRouteGraph.setFromId(busiMtnChannelRouteGraphs.get(0).getFromId());
            busiMtnChannelRouteGraph.setToId(busiMtnChannelRouteGraphs.get(size - 1).getFromId());
        }
        return busiMtnChannelRouteGraph;
    }

    /**
     * 生成业务-MTN Channel配置公共属性（路由图、路由表、其他属性）
     *
     * @param busiMtnChannelVo
     */
    @Transactional(rollbackFor = Exception.class)
    void insertBusiMtnChannelCommon(BusiMtnChannelVo busiMtnChannelVo) {
        //调用其他属性模版数据并新增
        ElementBusiMtnChannelOther elementBusiMtnChannelOther = elementBusiMtnChannelOtherMapper.selectElementBusiMtnChannelOtherTemplate();
        elementBusiMtnChannelOther.setId(IdUtils.simpleUUID());
        elementBusiMtnChannelOther.setMtnChannelId(busiMtnChannelVo.getId());
        elementBusiMtnChannelOther.setUpdateBy(SecurityUtils.getUsername());
        elementBusiMtnChannelOther.setUpdateTime(DateUtils.getNowDate());
        elementBusiMtnChannelOther.setCreateBy(SecurityUtils.getUsername());
        elementBusiMtnChannelOther.setCreateTime(DateUtils.getNowDate());
        elementBusiMtnChannelOther.setTemplateFlag("N");
        elementBusiMtnChannelOtherMapper.insertElementBusiMtnChannelOther(elementBusiMtnChannelOther);
        //生成路由图数据
        insertBusiMtnChannelRouteGraph(busiMtnChannelVo);

    }

    /**
     * MtnChannel生成路由图表
     *
     * @param
     */
    @Transactional(rollbackFor = Exception.class)
    public void insertBusiMtnChannelRouteGraph(BusiMtnChannelVo busiMtnChannelVo) {
        NetGroup netGroup = netGroupService.selectNetGroupById(busiMtnChannelVo.getStartElement());
        //源宿节点的父id:
        String parentId = netGroup.getParentId();
        Map<String, Integer> indexMap = new HashMap<String, Integer>();
        Set<String> idsUnique = new HashSet<>();
        List<TopoVo> topoVos1 = netGroupService.selectTopo(parentId);
        List<TopoVo> topoVos = new ArrayList<>();
        //获取总节点数组 并过滤mtn  PortMode 为disable 2.5修改
        for (TopoVo topoVo : topoVos1) {
            if (!CollectionUtils.isEmpty(topoVo.getLinkData())) {
                String startPortId = topoVo.getLinkData().get(0).getStartPortId();
                String endPortId = topoVo.getLinkData().get(0).getEndPortId();
                ElementPortMode startElementPortMode = elementPortModeMapper.selectElementPortModeById(startPortId);
                ElementPortMode endElementPortMode = elementPortModeMapper.selectElementPortModeById(endPortId);
                if ("disable".equals(startElementPortMode.getPortMode()) && "disable".equals(endElementPortMode.getPortMode())) {
                    topoVos.add(topoVo);//这里无法控制路由结构顺序 如1-3 ：预期结果 1-2  2-3
                }
            }
        }

        for (TopoVo topoVo : topoVos) {
            idsUnique.add(topoVo.getToId());
            idsUnique.add(topoVo.getFromId());
        }
        List<String> ids = new ArrayList<>(idsUnique);
        for (int i = 0; i < ids.size(); i++) {
            indexMap.put(ids.get(i), i);
        }
        Map<String, String> elementMap = new HashMap<String, String>();
        //构造双向线段
        for (TopoVo topoVo : topoVos) {
            elementMap.put(topoVo.getFromId(), topoVo.getFromName());
            elementMap.put(topoVo.getToId(), topoVo.getToName());

        }
        //获取总节点个数
        GraphUtil.Graph graph = new GraphUtil.Graph(ids.size());
        //构建路由对象  正向 反向
        for (int i = 0; i < topoVos.size(); i++) {
            graph.addEdge(indexMap.get(topoVos.get(i).getFromId()), indexMap.get(topoVos.get(i).getToId()));
            graph.addEdge(indexMap.get(topoVos.get(i).getToId()), indexMap.get(topoVos.get(i).getFromId()));

        }
        List<List<Integer>> paths = graph.allPathsSourceToDestination(indexMap.get(busiMtnChannelVo.getStartElement()), indexMap.get(busiMtnChannelVo.getEndElement()));
        List<List<String>> listIds = new ArrayList<>();
        Set<List<String>> listIdsUnq = new HashSet<>();

        for (List<Integer> path : paths) {
            List<String> list = new ArrayList<>();
            for (Integer integer : path) {
                list.add(ids.get(integer));
            }
            listIds.add(list);
            listIdsUnq.add(list);
        }
//        List<List<String>> finalRouteResult = GraphUtil.findTwoShortestArrays(listIds);
        //去重的线路set转list
        List<List<String>> filterList = new ArrayList<>(listIdsUnq);
        List<List<String>> filterList2 = new ArrayList<>();
        //是否有过滤约束
        hasFilterConstrant(busiMtnChannelVo);
        //todo 将所有的路由列举，添加过滤策略，过滤后的结果（工作、保护）入库
        List<List<NetElementLinkVo>> resultByFilter = filterRouteLineByConstraint(listIdsUnq, topoVos, busiMtnChannelVo);
        //获取两条最短路径
        List<List<NetElementLinkVo>> twoShortestInfos = findTwoShortestArrays(resultByFilter);
        for (List<NetElementLinkVo> netElementLinkVos : twoShortestInfos) {
            List<String> filters = new ArrayList<>();
            for (NetElementLinkVo netElementLinkVo : netElementLinkVos) {
                filters.add(netElementLinkVo.getStartElementId());
                filters.add(netElementLinkVo.getEndElementId());
            }
            List<String> toList = new ArrayList<>(filters);
            LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>(filters);
            List<String> arrayList = new ArrayList<>(linkedHashSet);
            filterList2.add(arrayList);
        }
        //声明两条最短路径
        List<List<String>> finalRouteResultNoFilter = new ArrayList<>();
        if (hasFilterFlag) {
            finalRouteResultNoFilter = GraphUtil.findTwoShortestArrays(filterList2);
        } else {
            finalRouteResultNoFilter = GraphUtil.findTwoShortestArrays(listIds);
        }
        /**
         * 1、如果是无保护存工作路径  直接取第一个最小数组,如果是1:1则取整个数组（两条最短路径），
         * 生成保护存工作路径、保护路径，然后构造fromId toId linkData
         * 2、将最短路径分隔成有向的n条线段
         * 3、将所有线段与topo图对比，获取属性全部信息
         * 4、将结果属性全部信息存入数据库
         */
        //原型中正反向时隙可保持一致
        if ("1".equals(busiMtnChannelVo.getFaultSize())) {
            if (redisCache.getCacheObject("maxTimeSlot") == null) {
                redisCache.setCacheObject("maxTimeSlot", 0);
            }
            Integer maxTimeSlot = redisCache.getCacheObject("maxTimeSlot");
            busiMtnChannelVo.setGlobalTimeSlot(String.valueOf(maxTimeSlot + 1));
            redisCache.setCacheObject("maxTimeSlot", maxTimeSlot + 1);
        } else {
            Integer maxTimeSlot = redisCache.getCacheObject("maxTimeSlot");
            String timeSlot = (maxTimeSlot + 1) + "-" + (maxTimeSlot + Integer.parseInt(busiMtnChannelVo.getFaultSize()));
            busiMtnChannelVo.setGlobalTimeSlot(timeSlot);
            redisCache.setCacheObject("maxTimeSlot", maxTimeSlot + Integer.parseInt(busiMtnChannelVo.getFaultSize()));
        }
        if ("无保护".equals(busiMtnChannelVo.getProtectType())) {
            if (finalRouteResultNoFilter.size() < 1 || twoShortestInfos.size() < 1) {
                throw new ServiceException("计算条件不足");
            }
            List<List<String>> workRoutes = new ArrayList<List<String>>();
            List<String> shortestRoute = finalRouteResultNoFilter.get(0);
            workRoutes.add(shortestRoute);
            //插入一条保护路径网元信息（附带顺序）
            insertBusiMtnChannelRouteElementsBatch(busiMtnChannelVo.getId(), shortestRoute, elementMap, "1");
            List<List<String>> allLines = GraphUtil.cutRouteToLine(shortestRoute);

            //生成路由图
            if (hasFilterFlag) {
                insertBusiMtnChannelRouteGraphCommon2(busiMtnChannelVo, twoShortestInfos.get(0), "1");
            } else {
                insertBusiMtnChannelRouteGraphCommon(busiMtnChannelVo, topoVos, allLines, "1");
            }
            //参考界面 正反可以保持一致
            int fgClientNum = globalIncrementService.getNextClientNumIncrementNumber();
            //统一变量   路由表 、sub表、fgclient表保持一致
            busiMtnChannelVo.setFgclientNum(String.valueOf(fgClientNum));
            //找到当前业务下所有网元，并入库至业务设备状态表并设置初始状态
            initBusiMtnChannelElementStatus(busiMtnChannelVo.getId(), workRoutes);
            //生成路由表 正反向
            insertBusiMtnChannelRouteTableCommon(busiMtnChannelVo, allLines,twoShortestInfos.get(0), "1", "1");
            insertBusiMtnChannelRouteTableCommon(busiMtnChannelVo, allLines,twoShortestInfos.get(0), "1", "2");

            //生成fgClient
            insertBusiMtnClientFg(busiMtnChannelVo, shortestRoute, "1");

        } else if ("MTN1+1保护".equals(busiMtnChannelVo.getProtectType())) {
            if (finalRouteResultNoFilter.size() < 2 || twoShortestInfos.size() < 2) {
                throw new ServiceException("计算条件不足");
            }
            //如果是MTN1+1保护 则取整个数组（两条最短路径），生成保护存工作路径、保护路径，然后构造fromId toId linkData
            //插入一条保护路径网元信息（附带顺序）
            insertBusiMtnChannelRouteElementsBatch(busiMtnChannelVo.getId(), finalRouteResultNoFilter.get(0), elementMap, "1");
            //线路1所有线段
            List<List<String>> workAllLines1 = GraphUtil.cutRouteToLine(finalRouteResultNoFilter.get(0));

            //生成路由图
            if (hasFilterFlag) {
                insertBusiMtnChannelRouteGraphCommon2(busiMtnChannelVo, twoShortestInfos.get(0), "1");
            } else {
                //将所有线段与topo图对比，获取属性全部信息
                insertBusiMtnChannelRouteGraphCommon(busiMtnChannelVo, topoVos, workAllLines1, "1");
            }

            //插入一条保护路径网元信息（附带顺序）
            insertBusiMtnChannelRouteElementsBatch(busiMtnChannelVo.getId(), finalRouteResultNoFilter.get(1), elementMap, "2");
            //参考界面 正反可以保持一致
            int fgClientNum = globalIncrementService.getNextClientNumIncrementNumber();
            //统一变量   路由表 、sub表、fgclient表保持一致
            busiMtnChannelVo.setFgclientNum(String.valueOf(fgClientNum));

            //找到当前业务下所有网元，并入库至业务设备状态表并设置初始状态
            initBusiMtnChannelElementStatus(busiMtnChannelVo.getId(), finalRouteResultNoFilter);
            //线路2所有线段
            List<List<String>> workAllLines2 = GraphUtil.cutRouteToLine(finalRouteResultNoFilter.get(1));

            //生成路由图
            if (hasFilterFlag) {
                    insertBusiMtnChannelRouteGraphCommon2(busiMtnChannelVo, twoShortestInfos.get(1), "2");
            } else {
                //将所有线段与topo图对比，获取属性全部信息
                insertBusiMtnChannelRouteGraphCommon(busiMtnChannelVo, topoVos, workAllLines2, "2");
            }
            insertBusiMtnChannelRouteTableCommon(busiMtnChannelVo, workAllLines1,twoShortestInfos.get(0), "1", "1");
            insertBusiMtnChannelRouteTableCommon(busiMtnChannelVo, workAllLines1,twoShortestInfos.get(0), "1", "2");
            insertBusiMtnChannelRouteTableCommon(busiMtnChannelVo, workAllLines2,twoShortestInfos.get(1),"2", "1");
            insertBusiMtnChannelRouteTableCommon(busiMtnChannelVo, workAllLines2,twoShortestInfos.get(1), "2", "2");

            //生成fgClient
            insertBusiMtnClientFg(busiMtnChannelVo, finalRouteResultNoFilter.get(1), "2");
        }
    }

    private List<List<NetElementLinkVo>> filterRouteLineByConstraint(Set<List<String>> allLines2, List<TopoVo> topoVos, BusiMtnChannelVo busiMtnChannelVo) {
        List<List<String>> allLines = new ArrayList<>(allLines2);
        List<TopoVo> topoVoSort = new ArrayList<>();
        List<MidVo> midLines = new ArrayList<>();
        //将计算的路由线路转换为topo
        for (int i = 0; i < allLines.size(); i++) {
            List<List<NetElementLinkVo>> subLines = new ArrayList<>();
            MidVo midVo = new MidVo();
            List<List<String>> lines = GraphUtil.cutRouteToLine(allLines.get(i));
            midVo.setElements(allLines.get(i));
            for (int j = 0; j < lines.size(); j++) {
                List<NetElementLinkVo> netElementLinkVos = new ArrayList<>();
                for (int k = 0; k < topoVos.size(); k++) {
                    if ((lines.get(j).get(0).equals(topoVos.get(k).getFromId()) && lines.get(j).get(1).equals(topoVos.get(k).getToId())) || (lines.get(j).get(1).equals(topoVos.get(k).getFromId()) && lines.get(j).get(0).equals(topoVos.get(k).getToId()))) {
                        topoVoSort.add(topoVos.get(k));
                        netElementLinkVos.add(topoVos.get(k).getLinkData().get(0));
                    }
                }
                subLines.add(netElementLinkVos);
            }
            midVo.setSubLines(subLines);
            midLines.add(midVo);
        }
        //所有路由结果
        List<List<NetElementLinkVo>> combinLineInfo = new ArrayList<>();
        for (int i = 0; i < midLines.size(); i++) {
            List<List<NetElementLinkVo>> combinations = combine(midLines.get(i).getSubLines());
            for (List<NetElementLinkVo> combinations1 : combinations) {
                for (NetElementLinkVo netElementLinkVo : combinations1) {
                    netElementLinkVo.setElements(midLines.get(i).getElements());
                }
            }
            combinLineInfo.addAll(combinations);
        }
        List<List<NetElementLinkVo>> finalResult = new ArrayList<>();
        //处理网元过滤
        BusiMtnChannelConstraint busiMtnChannelConstraint = new BusiMtnChannelConstraint();
        busiMtnChannelConstraint.setMtnChannelId(busiMtnChannelVo.getId());
        busiMtnChannelConstraint.setConstraintType("网元");
        List<BusiMtnChannelConstraint> busiMtnConstraints = busiMtnChannelConstraintMapper.selectBusiMtnChannelConstraintList(busiMtnChannelConstraint);
        if (!CollectionUtils.isEmpty(busiMtnConstraints)) {
            for (List<NetElementLinkVo> lineObjs : combinLineInfo) {
                for (BusiMtnChannelConstraint constraint : busiMtnConstraints) {
                    List<NetElementLinkVo> oneRoute = new ArrayList<>();
                    //处理网元包含、不包含逻辑
                    if ("包含".equals(constraint.getConstraintStrategy())) {
                        for (NetElementLinkVo lineObj : lineObjs) {
                            if (lineObj.getStartElementId().equals(constraint.getElementId()) || lineObj.getEndElementId().equals(constraint.getElementId())) {
                                oneRoute.add(lineObj);
                            }
                        }
                    } else {
                        for (NetElementLinkVo lineObj : lineObjs) {
                            if (!lineObj.getStartElementId().equals(constraint.getElementId()) && !lineObj.getEndElementId().equals(constraint.getElementId())) {
                                oneRoute.add(lineObj);
                            }
                        }
                    }
                    if (oneRoute.size() > 0) {
                        finalResult.add(oneRoute);
                    }
                }
            }
        } else {
            finalResult = combinLineInfo;
        }

        List<List<NetElementLinkVo>> finalResult2 = new ArrayList<>();
        //处理端口过滤
        busiMtnChannelConstraint.setConstraintType("端口");
        List<BusiMtnChannelConstraint> busiMtnConstraints2 = busiMtnChannelConstraintMapper.selectBusiMtnChannelConstraintList(busiMtnChannelConstraint);
        if (!CollectionUtils.isEmpty(busiMtnConstraints2)) {
            for (List<NetElementLinkVo> lineObjs : finalResult) {
                List<NetElementLinkVo> oneRoute = new ArrayList<>();
                for (BusiMtnChannelConstraint constraint : busiMtnConstraints2) {
                    //处理网元包含、不包含逻辑
                    if ("包含".equals(constraint.getConstraintStrategy())) {
                        for (NetElementLinkVo lineObj : lineObjs) {
                            if (lineObj.getStartPortId().equals(constraint.getPortId()) || lineObj.getEndPortId().equals(constraint.getPortId())) {
//                                oneRoute.add(lineObj);
                                finalResult2.add(lineObjs);
                            }
                        }
                    } else {
                        for (NetElementLinkVo lineObj : lineObjs) {
                            if (!lineObj.getStartPortId().equals(constraint.getPortId()) && !lineObj.getEndPortId().equals(constraint.getPortId())) {
//                                oneRoute.add(lineObj)
                                 finalResult2.add(lineObjs);;
                            }
                        }
                    }
                 /*   if (oneRoute.size() > 0) {
                        finalResult2.add(oneRoute);
                    }*/
                }
            }
        } else {
            finalResult2 = finalResult;
        }

        return finalResult2;

    }

    /**
     * 是否有过滤约束
     *
     * @param busiMtnChannelVo
     * @return
     */
    boolean hasFilterConstrant(BusiMtnChannelVo busiMtnChannelVo) {
        BusiMtnChannelConstraint busiMtnChannelConstraint = new BusiMtnChannelConstraint();
        busiMtnChannelConstraint.setMtnChannelId(busiMtnChannelVo.getId());
        List<BusiMtnChannelConstraint> busiMplstpConstraints = busiMtnChannelConstraintMapper.selectBusiMtnChannelConstraintList(busiMtnChannelConstraint);
        hasFilterFlag = !CollectionUtils.isEmpty(busiMplstpConstraints);
        return hasFilterFlag;
    }

    /**
     * 找到当前业务下所有网元，并入库至业务设备状态表并设置初始状态
     *
     * @param mtnChannelId
     * @param finalRouteResult
     */
    private void initBusiMtnChannelElementStatus(String mtnChannelId, List<List<String>> finalRouteResult) {
        HashSet<String> uniqueElement = new HashSet<>();
        //找出不重复的网元
        for (List<String> oneRoute : finalRouteResult) {
            for (String elementId : oneRoute) {
                uniqueElement.add(elementId);
            }
        }
        //入库至业务设备状态表并设置初始状态
        for (String elementId : uniqueElement) {
            BusiElementStatus busiElementStatus = new BusiElementStatus();
            busiElementStatus.setElementId(elementId);
            busiElementStatus.setBusiId(mtnChannelId);
            busiElementStatus.setId(IdUtils.simpleUUID());
            busiElementStatus.setStatus("0");
            busiElementStatus.setBusiType(ElementConstants.BUSI_FG_CHANNEL);
            busiElementStatus.setCreateBy(SecurityUtils.getUsername());
            busiElementStatus.setCreateTime(DateUtils.getNowDate());
            busiElementStatusMapper.insertBusiElementStatus(busiElementStatus);
        }
    }

    /**
     * 生成ClientFg
     *
     * @param busiMtnChannelVo
     * @param shortestRoute
     * @param routeType
     */
    private void insertBusiMtnClientFg(BusiMtnChannelVo busiMtnChannelVo, List<String> shortestRoute, String routeType) {
        //如果路由只有两个节点
        if (shortestRoute.size() == 2) {
            insertElementBusiMtnclientFgCommon(busiMtnChannelVo, shortestRoute.get(0), routeType, "1");
            insertElementBusiMtnclientFgCommon(busiMtnChannelVo, shortestRoute.get(1), routeType, "1");
        } else {
            for (int i = 0; i < shortestRoute.size(); i++) {
                if (i == 0) {
                    //1=：源,2=：宿,3=：,过=站
                    insertElementBusiMtnclientFgCommon(busiMtnChannelVo, shortestRoute.get(i), routeType, "1");
                } else if (i == shortestRoute.size() - 1) {
                    //宿
                    insertElementBusiMtnclientFgCommon(busiMtnChannelVo, shortestRoute.get(i), routeType, "2");
                } else {
                    if ("MTN1+1保护".equals(busiMtnChannelVo.getProtectType())) {
                        //过站
                        ElementBusiMtnclientFg elementBusiMtnclientFg1 = insertElementBusiMtnclientFgCommon(busiMtnChannelVo, shortestRoute.get(i), routeType, "3");
                        ElementBusiMtnclientFg elementBusiMtnclientFg2 = insertElementBusiMtnclientFgCommon(busiMtnChannelVo, shortestRoute.get(i), routeType, "3");
                        //生成过站数据
                        BusiMtnChannelCross busiMtnChannelCross = new BusiMtnChannelCross();
                        busiMtnChannelCross.setId(IdUtils.simpleUUID());
                        busiMtnChannelCross.setMtnChannelId(busiMtnChannelVo.getId());
                        busiMtnChannelCross.setFaultSize("10M");
                        busiMtnChannelCross.setCreateBy(SecurityUtils.getUsername());
                        busiMtnChannelCross.setCreateTime(DateUtils.getNowDate());
                        busiMtnChannelCross.setUpdateBy(SecurityUtils.getUsername());
                        busiMtnChannelCross.setUpdateTime(DateUtils.getNowDate());
                        busiMtnChannelCross.setElementId(shortestRoute.get(i));//过站节点的id
                        busiMtnChannelCross.setStartFgClientId(elementBusiMtnclientFg1.getId());//fgclinet主健  取名歧义 应该是过站fg1  过站2fgid
                        busiMtnChannelCross.setEndFgClientId(elementBusiMtnclientFg2.getId());//fgclinet主健
                        busiMtnChannelCross.setCrossName("mtncross_" + globalIncrementService.getNextMtnCrossIdIncrementNumber());
                        busiMtnChannelCrossMapper.insertBusiMtnChannelCross(busiMtnChannelCross);

                    }

                }
            }
        }


    }

    private void insertMtnCross(BusiMtnChannelVo busiMtnChannelVo, String elementId) {
        //过站数据 网元id


    }


    /**
     * 生成fgclient数据
     *
     * @param busiMtnChannelVo
     * @param elementId
     */
    private ElementBusiMtnclientFg insertElementBusiMtnclientFgCommon(BusiMtnChannelVo busiMtnChannelVo, String elementId, String routeType, String elementType) {
        ElementBusiMtnclientFg elementBusiMtnclientFg = new ElementBusiMtnclientFg();
        elementBusiMtnclientFg.setId(IdUtils.simpleUUID());
        elementBusiMtnclientFg.setMtnChannelId(busiMtnChannelVo.getId());
        elementBusiMtnclientFg.setElementId(elementId);
        if ("3".equals(elementType)) {
            //过站的时候 该id不能保持一致
            elementBusiMtnclientFg.setName("mtntunnel" + globalIncrementService.getNextMtnFgClientNumIdIncrementNumber());
        } else {
            elementBusiMtnclientFg.setName("mtntunnel" + busiMtnChannelVo.getFgclientNum());
        }

        elementBusiMtnclientFg.setElementType(elementType);
//        elementBusiMtnclientFg.setRouteType(routeType);  fg不分工作保护
        elementBusiMtnclientFg.setCreateBy(SecurityUtils.getUsername());
        elementBusiMtnclientFg.setCreateTime(DateUtils.getNowDate());
        elementBusiMtnclientFg.setUpdateBy(SecurityUtils.getUsername());
        elementBusiMtnclientFg.setUpdateTime(DateUtils.getNowDate());
        elementBusiMtnclientFgMapper.insertElementBusiMtnclientFg(elementBusiMtnclientFg);
        //生成mtn subclient信息  工作一条  保护两条
        if ("无保护".equals(busiMtnChannelVo.getProtectType())) {
            insertBusiMtnChannelSubClient("1", busiMtnChannelVo, elementBusiMtnclientFg.getId());
        } else {
            if (!"3".equals(elementType)) {
                //源宿
                insertBusiMtnChannelSubClient("1", busiMtnChannelVo, elementBusiMtnclientFg.getId());
                insertBusiMtnChannelSubClient("2", busiMtnChannelVo, elementBusiMtnclientFg.getId());
            } else {
                //过站
                insertBusiMtnChannelSubClient("1", busiMtnChannelVo, elementBusiMtnclientFg.getId());
            }

        }
        return elementBusiMtnclientFg;
    }

    /**
     * 插入MtnChannel路由表公共方法
     *
     * @param busiMtnChannelVo
     * @param allLines
     * @param routeType
     */
    private void insertBusiMtnChannelRouteTableCommon(BusiMtnChannelVo busiMtnChannelVo, List<List<String>> allLines,List<NetElementLinkVo> links, String routeType, String routeDirection) {
        //是否有路由约束
        if (hasFilterFlag) {
            //正向
            if ("1".equals(routeDirection)) {
                for (int i = 0; i < links.size(); i++) {
                    NetElementLinkVo link = links.get(i);
                    insertBusiMtnChannelRouteTable(busiMtnChannelVo, routeDirection, routeType, link.getStartElementId(), link.getStartPortId(), link.getStartPort(),busiMtnChannelVo.getFgclientNum());
                    insertBusiMtnChannelRouteTable(busiMtnChannelVo, routeDirection, routeType, link.getEndElementId(), link.getEndPortId(), link.getEndPort(), busiMtnChannelVo.getFgclientNum());
                }
            } else {
                //反向
                for (int i = links.size(); i > 0; i--) {
                    NetElementLinkVo link = links.get(i - 1);
                    insertBusiMtnChannelRouteTable(busiMtnChannelVo, routeDirection, routeType, link.getEndElementId(), link.getEndPortId(), link.getEndPort(), busiMtnChannelVo.getFgclientNum());
                    insertBusiMtnChannelRouteTable(busiMtnChannelVo, routeDirection, routeType, link.getStartElementId(), link.getStartPortId(), link.getStartPort(), busiMtnChannelVo.getFgclientNum());
                }
            }


        } else {
            BusiMtnChannelRouteGraph busiMtnChannelRouteGraph = new BusiMtnChannelRouteGraph();
            busiMtnChannelRouteGraph.setMtnChannelId(busiMtnChannelVo.getId());
            busiMtnChannelRouteGraph.setRouteType(routeType);
            //查询路由图 包含构造的逆向数据
            List<BusiMtnChannelRouteGraph> busiMtnChannelRouteGraphs = busiMtnChannelRouteGraphMapper.selectBusiMtnChannelRouteGraphList(busiMtnChannelRouteGraph);
            //过滤非构造线段属性
            List<BusiMtnChannelRouteGraph> filterResult = new ArrayList<>();
            //按照顺序分割好的线段与路由图对比取 link属性
            for (int i = 0; i < allLines.size(); i++) {
                for (int j = 0; j < busiMtnChannelRouteGraphs.size(); j++) {
                    if (allLines.get(i).get(0).equals(busiMtnChannelRouteGraphs.get(j).getFromId()) && allLines.get(i).get(1).equals(busiMtnChannelRouteGraphs.get(j).getToId())) {
                        filterResult.add(busiMtnChannelRouteGraphs.get(j));
                    }
                }
            }
            //正向
            if ("1".equals(routeDirection)) {
                for (int i = 0; i < filterResult.size(); i++) {
                    BusiMtnChannelRouteGraph graph = filterResult.get(i);
                    insertBusiMtnChannelRouteTable(busiMtnChannelVo, routeDirection, routeType, graph.getFromId(), graph.getStartPortId(), graph.getStartPort(), busiMtnChannelVo.getFgclientNum());
                    insertBusiMtnChannelRouteTable(busiMtnChannelVo, routeDirection, routeType, graph.getToId(), graph.getEndPortId(), graph.getEndPort(), busiMtnChannelVo.getFgclientNum());
                }
            } else {
                int j = 0;
                for (int i = filterResult.size(); i > 0; i--) {
                    BusiMtnChannelRouteGraph graph = filterResult.get(i - 1);
                    insertBusiMtnChannelRouteTable(busiMtnChannelVo, routeDirection, routeType, graph.getToId(), graph.getEndPortId(), graph.getEndPort(), busiMtnChannelVo.getFgclientNum());
                    insertBusiMtnChannelRouteTable(busiMtnChannelVo, routeDirection, routeType, graph.getFromId(), graph.getStartPortId(), graph.getStartPort(), busiMtnChannelVo.getFgclientNum());
                    j++;
                }
            }
        }

    }

    private void insertBusiMtnChannelRouteTable(BusiMtnChannelVo busiMtnChannelVo, String routeDirection, String routeType, String elementId, String portId, String portName, String fgClientNum) {
        BusiMtnChannelRouteTable busiMtnChannelRouteTable = new BusiMtnChannelRouteTable();
        busiMtnChannelRouteTable.setId(IdUtils.simpleUUID());
        busiMtnChannelRouteTable.setMtnChannelId(busiMtnChannelVo.getId());
        busiMtnChannelRouteTable.setRouteDirection(routeDirection);
        busiMtnChannelRouteTable.setRouteType(routeType);
        busiMtnChannelRouteTable.setElementId(elementId);
        busiMtnChannelRouteTable.setPortId(portId);
        busiMtnChannelRouteTable.setPortName("mtn-fgclient" + globalIncrementService.getNextFgClientIncrementNumber());
        busiMtnChannelRouteTable.setTerminalLabel("");
        busiMtnChannelRouteTable.setClientNum(fgClientNum);//自增
        //按照主表时隙个数取值，如1对应0，2对应0-1，3对应0-2  与subclient 保持一致
//        busiMtnChannelRouteTable.setFaultId("0-"+ (Integer.valueOf(busiMtnChannelVo.getFaultSize())+1));
        busiMtnChannelRouteTable.setFaultId(busiMtnChannelVo.getGlobalTimeSlot());
        busiMtnChannelRouteTable.setCreateBy(SecurityUtils.getUsername());
        busiMtnChannelRouteTable.setCreateTime(DateUtils.getNowDate());
        busiMtnChannelRouteTable.setUpdateBy(SecurityUtils.getUsername());
        busiMtnChannelRouteTable.setUpdateTime(DateUtils.getNowDate());
        busiMtnChannelRouteTableMapper.insertBusiMtnChannelRouteTable(busiMtnChannelRouteTable);
    }

    /**
     * 插入业务Mtn-channel 路由图公共方法
     *
     * @param busiMtnChannelVo
     * @param topoVos
     * @param workAllLines1
     * @param routeType
     */
    public void insertBusiMtnChannelRouteGraphCommon(BusiMtnChannelVo busiMtnChannelVo, List<TopoVo> topoVos, List<List<String>> workAllLines1, String routeType) {
        String pathId1 = IdUtils.simpleUUID();
        for (int j = 0; j < topoVos.size(); j++) {
            for (int i = 0; i < workAllLines1.size(); i++) {
                //用返回最短路径结果与topo图对比，获取属性全部信息
                if ((topoVos.get(j).getFromId().equals(workAllLines1.get(i).get(0)) && topoVos.get(j).getToId().equals(workAllLines1.get(i).get(1))) || (topoVos.get(j).getFromId().equals(workAllLines1.get(i).get(1)) && topoVos.get(j).getToId().equals(workAllLines1.get(i).get(0)))) {
                    //避免重复插入脏数据
                    List<BusiMtnChannelRouteGraph> busiMtnChannelRouteGraphs1 = validbusiMtnChannelRouteGraph(busiMtnChannelVo, topoVos.get(j), pathId1);
                    if (CollectionUtils.isEmpty(busiMtnChannelRouteGraphs1)) {

                        BusiMtnChannelRouteGraph routeGraph = new BusiMtnChannelRouteGraph();
                        if (StringUtils.isEmpty(routeGraph.getId())) {
                            routeGraph.setId(IdUtils.simpleUUID());
                        }
                        routeGraph.setRouteType(routeType);
                        //线路id  用于区分同一个MtnChannelId下 的多条线路
                        routeGraph.setPathId(pathId1);
                        //主表主键
                        routeGraph.setMtnChannelId(busiMtnChannelVo.getId());
                        routeGraph.setFromId(workAllLines1.get(i).get(0));
                        routeGraph.setToId(workAllLines1.get(i).get(1));
                        routeGraph.setFromName(topoVos.get(j).getFromName());
                        routeGraph.setToName(topoVos.get(j).getToName());
                        routeGraph.setStartPortId(topoVos.get(j).getLinkData().get(0).getStartPortId());
                        routeGraph.setStartPort(topoVos.get(j).getLinkData().get(0).getStartPort());
                        routeGraph.setEndPortId(topoVos.get(j).getLinkData().get(0).getEndPortId());
                        routeGraph.setEndPort(topoVos.get(j).getLinkData().get(0).getEndPort());
                        routeGraph.setCreateBy(SecurityUtils.getUsername());
                        routeGraph.setCreateTime(DateUtils.getNowDate());
                        routeGraph.setUpdateBy(SecurityUtils.getUsername());
                        routeGraph.setUpdateTime(DateUtils.getNowDate());
                        busiMtnChannelRouteGraphMapper.insertBusiMtnChannelRouteGraph(routeGraph);
                        //插入一条与实际方向相反的数据，方便前端展示双向效果
                        routeGraph.setId(IdUtils.simpleUUID());
                        routeGraph.setFromId(workAllLines1.get(i).get(1));
                        routeGraph.setToId(workAllLines1.get(i).get(0));
                        routeGraph.setFromName(topoVos.get(j).getToName());
                        routeGraph.setToName(topoVos.get(j).getFromName());
                        routeGraph.setStartPortId(topoVos.get(j).getLinkData().get(0).getEndPortId());
                        routeGraph.setEndPortId(topoVos.get(j).getLinkData().get(0).getStartPortId());
                        routeGraph.setStartPort(topoVos.get(j).getLinkData().get(0).getEndPort());
                        routeGraph.setEndPort(topoVos.get(j).getLinkData().get(0).getStartPort());
                        routeGraph.setCreateTime(DateUtils.getNowDate());
                        routeGraph.setUpdateTime(DateUtils.getNowDate());
                        busiMtnChannelRouteGraphMapper.insertBusiMtnChannelRouteGraph(routeGraph);
                    }
                }
            }
        }
    }

    private void insertBusiMtnChannelRouteGraphCommon2(BusiMtnChannelVo busiMtnChannelVo, List<NetElementLinkVo> randomLinks, String routeType) {
        List<List<String>> allLines2 = new ArrayList<>();
        List<NetElementLinkVo> netElementLinkVos = new ArrayList<>();
        allLines2 = GraphUtil.cutRouteToLine(randomLinks.get(0).getElements());
        //将topo图按照线段排序
        for (int i = 0; i < allLines2.size(); i++) {
            for (int j = 0; j < randomLinks.size(); j++) {
                if ((allLines2.get(i).get(0).equals(randomLinks.get(j).getStartElementId()) && allLines2.get(i).get(1).equals(randomLinks.get(j).getEndElementId())) || (allLines2.get(i).get(1).equals(randomLinks.get(j).getStartElementId()) && allLines2.get(i).get(0).equals(randomLinks.get(j).getEndElementId()))) {
                    netElementLinkVos.add(randomLinks.get(j));
                }
            }
        }
        String pathId1 = IdUtils.simpleUUID();
        List<String> oneRoute = new ArrayList<>();
        for (int j = 0; j < netElementLinkVos.size(); j++) {
            oneRoute = netElementLinkVos.get(j).getElements();
            List<List<String>> allLines = GraphUtil.cutRouteToLine(oneRoute);
            //避免重复插入脏数据
            List<BusiMtnChannelRouteGraph> busiMtnChannelRouteGraphs1 = validbusiMtnChannelRouteGraph2(busiMtnChannelVo, netElementLinkVos.get(j), pathId1);
            if (CollectionUtils.isEmpty(busiMtnChannelRouteGraphs1)) {

                BusiMtnChannelRouteGraph routeGraph = new BusiMtnChannelRouteGraph();
                if (StringUtils.isEmpty(routeGraph.getId())) {
                    routeGraph.setId(IdUtils.simpleUUID());
                }
                routeGraph.setRouteType(routeType);
                //线路id  用于区分同一个MtnChannelId下 的多条线路
                routeGraph.setPathId(pathId1);
                //主表主键
                routeGraph.setMtnChannelId(busiMtnChannelVo.getId());
                routeGraph.setFromId(allLines.get(j).get(0));
                routeGraph.setToId(allLines.get(j).get(1));
                routeGraph.setFromName(netElementLinkVos.get(j).getStartName());
                routeGraph.setToName(netElementLinkVos.get(j).getEndName());
                routeGraph.setStartPortId(netElementLinkVos.get(j).getStartPortId());
                routeGraph.setStartPort(netElementLinkVos.get(j).getStartPort());
                routeGraph.setEndPortId(netElementLinkVos.get(j).getEndPortId());
                routeGraph.setEndPort(netElementLinkVos.get(j).getEndPort());
                routeGraph.setCreateBy(SecurityUtils.getUsername());
                routeGraph.setCreateTime(DateUtils.getNowDate());
                routeGraph.setUpdateBy(SecurityUtils.getUsername());
                routeGraph.setUpdateTime(DateUtils.getNowDate());
                busiMtnChannelRouteGraphMapper.insertBusiMtnChannelRouteGraph(routeGraph);
                //插入一条与实际方向相反的数据，方便前端展示双向效果
                routeGraph.setId(IdUtils.simpleUUID());
                routeGraph.setFromId(allLines.get(j).get(1));
                routeGraph.setToId(allLines.get(j).get(0));
                routeGraph.setFromName(netElementLinkVos.get(j).getEndName());
                routeGraph.setToName(netElementLinkVos.get(j).getStartName());
                routeGraph.setStartPortId(netElementLinkVos.get(j).getEndPortId());
                routeGraph.setEndPortId(netElementLinkVos.get(j).getStartPortId());
                routeGraph.setStartPort(netElementLinkVos.get(j).getEndPort());
                routeGraph.setEndPort(netElementLinkVos.get(j).getStartPort());
                routeGraph.setCreateTime(DateUtils.getNowDate());
                routeGraph.setUpdateTime(DateUtils.getNowDate());
                busiMtnChannelRouteGraphMapper.insertBusiMtnChannelRouteGraph(routeGraph);
            }
        }

    }

    private List<BusiMtnChannelRouteGraph> validbusiMtnChannelRouteGraph2(BusiMtnChannelVo busiMtnChannelVo, NetElementLinkVo link, String pathId) {
        BusiMtnChannelRouteGraph busiMtnChannelRouteGraph = new BusiMtnChannelRouteGraph();
        busiMtnChannelRouteGraph.setMtnChannelId(busiMtnChannelVo.getId());
        busiMtnChannelRouteGraph.setFromId(link.getStartElementId());
        busiMtnChannelRouteGraph.setToId(link.getEndElementId());
        busiMtnChannelRouteGraph.setPathId(pathId);
        return busiMtnChannelRouteGraphMapper.selectBusiMtnChannelRouteGraphList(busiMtnChannelRouteGraph);
    }

    /**
     * 插入路由图网元（顺序）对象
     *
     * @param mtnChannelId
     * @param shortestRoute
     * @param elementMap
     */
    private void insertBusiMtnChannelRouteElementsBatch(String mtnChannelId, List<String> shortestRoute, Map<String, String> elementMap, String routeType) {
        for (String elementId : shortestRoute) {
            BusiMtnChannelRouteElements busiMtnChannelRouteElements = new BusiMtnChannelRouteElements();
            busiMtnChannelRouteElements.setId(IdUtils.simpleUUID());
            busiMtnChannelRouteElements.setMtnChannelId(mtnChannelId);
            busiMtnChannelRouteElements.setElementId(elementId);
            busiMtnChannelRouteElements.setElementName(elementMap.get(elementId));
            busiMtnChannelRouteElements.setRouteType(routeType);
            busiMtnChannelRouteElements.setCreateBy(SecurityUtils.getUsername());
            busiMtnChannelRouteElements.setCreateTime(DateUtils.getNowDate());
            busiMtnChannelRouteElements.setUpdateBy(SecurityUtils.getUsername());
            busiMtnChannelRouteElements.setUpdateTime(DateUtils.getNowDate());
            busiMtnChannelRouteElementsMapper.insertBusiMtnChannelRouteElements(busiMtnChannelRouteElements);
        }
    }

    /**
     * 校验路由图表数据
     * 避免重复插入脏路由图表数据
     */
    List<BusiMtnChannelRouteGraph> validbusiMtnChannelRouteGraph(BusiMtnChannelVo busiMtnChannelVo, TopoVo topoVo, String pathId) {
        BusiMtnChannelRouteGraph busiMtnChannelRouteGraphSearchParam = new BusiMtnChannelRouteGraph();
        busiMtnChannelRouteGraphSearchParam.setMtnChannelId(busiMtnChannelVo.getId());
        busiMtnChannelRouteGraphSearchParam.setFromId(topoVo.getFromId());
        busiMtnChannelRouteGraphSearchParam.setToId(topoVo.getToId());
        busiMtnChannelRouteGraphSearchParam.setPathId(pathId);
        return busiMtnChannelRouteGraphMapper.selectBusiMtnChannelRouteGraphList(busiMtnChannelRouteGraphSearchParam);
    }

    /**
     * 新增保护属性对象
     *
     * @param busiMtnChannelVo
     */
    public void insertBusiMtnChannelProtect(BusiMtnChannelVo busiMtnChannelVo) {
        ElementBusiMtnChannelProtect elementBusiMtnChannelProtect = elementBusiMtnChannelProtectMapper.selectElementBusiMtnChannelProtectTemplate();
        elementBusiMtnChannelProtect.setId(IdUtils.simpleUUID());
        elementBusiMtnChannelProtect.setMtnChannelId(busiMtnChannelVo.getId());
        elementBusiMtnChannelProtect.setUpdateBy(SecurityUtils.getUsername());
        elementBusiMtnChannelProtect.setUpdateTime(DateUtils.getNowDate());
        elementBusiMtnChannelProtect.setCreateBy(SecurityUtils.getUsername());
        elementBusiMtnChannelProtect.setCreateTime(DateUtils.getNowDate());
        elementBusiMtnChannelProtect.setStartElementId(busiMtnChannelVo.getStartElement());
        elementBusiMtnChannelProtect.setEndElementId(busiMtnChannelVo.getEndElement());
        elementBusiMtnChannelProtect.setTemplateFlag("N");
        elementBusiMtnChannelProtectMapper.insertElementBusiMtnChannelProtect(elementBusiMtnChannelProtect);
    }

    /**
     * 新增oam对象
     *
     * @param busiMtnChannelVo
     * @param routeType        路径类型 1：工作  2：保护
     * @param elementId        源、宿网元id
     */
    public void insertBusiMtnChannelOam(BusiMtnChannelVo busiMtnChannelVo, String routeType, String elementId, String nodeType) {
        ElementBusiMtnChannelOam elementBusiMtnChannelOam = elementBusiMtnChannelOamMapper.selectElementBusiMtnChannelOamTemplate();
        elementBusiMtnChannelOam.setId(IdUtils.simpleUUID());
        //工作路径-源网元
        elementBusiMtnChannelOam.setProtectType(routeType);
        elementBusiMtnChannelOam.setElementId(elementId);
        elementBusiMtnChannelOam.setMtnChannelId(busiMtnChannelVo.getId());
        elementBusiMtnChannelOam.setUpdateBy(SecurityUtils.getUsername());
        elementBusiMtnChannelOam.setUpdateTime(DateUtils.getNowDate());
        elementBusiMtnChannelOam.setCreateBy(SecurityUtils.getUsername());
        elementBusiMtnChannelOam.setCreateTime(DateUtils.getNowDate());
        elementBusiMtnChannelOam.setTemplateFlag("N");
        elementBusiMtnChannelOam.setNodeType(nodeType);
        elementBusiMtnChannelOamMapper.insertElementBusiMtnChannelOam(elementBusiMtnChannelOam);
    }

    /**
     * 新增细粒度业务盘保护组对象
     *
     * @param busiMtnChannelVo
     * @param routeType        路径类型 1：工作  2：保护
     * @param elementType      网元类型 1：源  2：宿
     * @param routeGraph
     */
    public void insertBusiMtnChannelGrain(BusiMtnChannelVo busiMtnChannelVo, String routeType, String elementType, BusiMtnChannelRouteGraph routeGraph) {
        //创建源保护组对象
        ElementBusiMtnChannelGrain grain = new ElementBusiMtnChannelGrain();
        grain.setId(IdUtils.simpleUUID());
        grain.setMtnChannelId(busiMtnChannelVo.getId());
        grain.setRouteType(routeType);
        grain.setElementType(elementType);
        if ("1".equals(elementType)) {
            grain.setElementId(busiMtnChannelVo.getStartElement());
        } else {
            grain.setElementId(busiMtnChannelVo.getEndElement());
        }
        //插入端口id 、名称
        grain.setPortId(routeGraph.getStartPortId());
        grain.setPortName(routeGraph.getStartPort());
        grain.setGrainProtect(busiMtnChannelVo.getStartProtectGroupId());
        grain.setCreateBy(SecurityUtils.getUsername());
        grain.setCreateTime(DateUtils.getNowDate());
        grain.setUpdateBy(SecurityUtils.getUsername());
        grain.setUpdateTime(DateUtils.getNowDate());
        busiMtnChannelGrainMapper.insertElementBusiMtnChannelGrain(grain);
    }

    /**
     * 修改业务-MTN Channel配置
     *
     * @param busiMtnChannel 业务-MTN Channel配置
     * @return 结果
     */
    @Override
    public int updateBusiMtnChannel(BusiMtnChannel busiMtnChannel) {
        busiMtnChannel.setUpdateBy(SecurityUtils.getUsername());
        busiMtnChannel.setUpdateTime(DateUtils.getNowDate());
        ElementBusiMtnclientFg busiMtnclientFg = new ElementBusiMtnclientFg();
        busiMtnclientFg.setMtnChannelId(busiMtnChannel.getId());
        //点击完成时更新删除标识
        busiMtnclientFg.setDelFlag("0");
        elementBusiMtnclientFgMapper.batchUpdateElementBusiMtnclientFgDelFlag(busiMtnclientFg);
        return busiMtnChannelMapper.updateBusiMtnChannel(busiMtnChannel);
    }

    /**
     * 批量删除业务-MTN Channel配置
     *
     * @param ids 需要删除的业务-MTN Channel配置主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteBusiMtnChannelByIds(String[] ids) {
        // 2025-07-17 先删除veth
        for (String id : ids) {
            elementPortMtnEvthMapper.deleteElementPortMtnEvthByChannelId(id);
        }
        return busiMtnChannelMapper.deleteBusiMtnChannelByIds(ids);
    }

    /**
     * 删除业务-MTN Channel配置信息
     *
     * @param id 业务-MTN Channel配置主键
     * @return 结果
     */
    @Override
    public int deleteBusiMtnChannelById(String id) {
        return busiMtnChannelMapper.deleteBusiMtnChannelById(id);
    }

    @Override
    public List<BusiMtnChannelListVo> selectBusiMtnChannelClientList(BusiMtnChannelListVo busiMtnChannel) {
        return busiMtnChannelMapper.selectBusiMtnChannelClientList(busiMtnChannel);
    }

    /**
     * 新增接口模式，虚拟纤
     * 1、查询mtn-veth表
     * 2、新增虚拟port_mode
     * 3、新增虚拟连纤
     *
     * @param mtnChannelId
     * @return
     */
    @Override
    public int insertVirtualInterface(String mtnChannelId) {
        int linkResult = 0;
        ElementBusiMtnChannelVeth elementBusiMtnChannelVeth = elementBusiMtnChannelVethMapper.selectElementBusiMtnChannelVethByMtnId(mtnChannelId);
        if (elementBusiMtnChannelVeth != null) {
            //取源宿信息
            ElementPortMtnEvth startElementPortMtnEvth = elementPortMtnEvthMapper.selectElementPortMtnEvthById(elementBusiMtnChannelVeth.getStartElementVethId());
            //插入portmode表
            ElementPortMode startElementPortMode = new ElementPortMode();
            startElementPortMode.setId(IdUtils.simpleUUID());
            startElementPortMode.setElementId(startElementPortMtnEvth.getElementId());
            startElementPortMode.setPortName(startElementPortMtnEvth.getTerminalName());
            startElementPortMode.setPortMode("veth");
            startElementPortMode.setCreateBy(SecurityUtils.getUsername());
            startElementPortMode.setCreateTime(DateUtils.getNowDate());
            elementPortModeMapper.insertElementPortMode(startElementPortMode);

            ElementPortMtnEvth endElementPortMtnEvth = elementPortMtnEvthMapper.selectElementPortMtnEvthById(elementBusiMtnChannelVeth.getEndElementVethId());
            //插入portmode表
            ElementPortMode endElementPortMode = new ElementPortMode();
            endElementPortMode.setId(IdUtils.simpleUUID());
            endElementPortMode.setElementId(endElementPortMtnEvth.getElementId());
            endElementPortMode.setPortName(endElementPortMtnEvth.getTerminalName());
            endElementPortMode.setPortMode("veth");
            endElementPortMode.setCreateBy(SecurityUtils.getUsername());
            endElementPortMode.setCreateTime(DateUtils.getNowDate());
            elementPortModeMapper.insertElementPortMode(endElementPortMode);
            //新增连纤
            NetElementLink netElementLink = new NetElementLink();
            netElementLink.setLinkName("link"+globalIncrementService.getNextOamIdIncrementNumber());
            netElementLink.setId(IdUtils.simpleUUID());
            netElementLink.setStartElementId(startElementPortMtnEvth.getElementId());
            netElementLink.setEndElementId(endElementPortMtnEvth.getElementId());
            netElementLink.setStartPortId(startElementPortMode.getId());
            netElementLink.setEndPortId(endElementPortMode.getId());
            netElementLink.setCreateBy(SecurityUtils.getUsername());
            netElementLink.setCreateTime(DateUtils.getNowDate());
            netElementLink.setLinkType("2");
            linkResult = netElementLinkMapper.insertNetElementLink(netElementLink);
        }
        return linkResult;
    }

    /**
     * 删除接口模式，虚拟纤
     * 1、查询mtn-veth表
     * 2、删除虚拟port_mode
     * 3、删除虚拟连纤
     *
     * @param mtnChannelId
     * @return
     */
    @Override
    public int deleteVirtualInterface(String mtnChannelId) {
        int linkResult = 0;
        ElementBusiMtnChannelVeth elementBusiMtnChannelVeth = elementBusiMtnChannelVethMapper.selectElementBusiMtnChannelVethByMtnId(mtnChannelId);
        if (elementBusiMtnChannelVeth != null) {
            //取源宿信息 删除portmode表
            ElementPortMtnEvth startElementPortMtnEvth = elementPortMtnEvthMapper.selectElementPortMtnEvthById(elementBusiMtnChannelVeth.getStartElementVethId());
            ElementPortMode startElementPortMode = elementPortModeMapper.selectElementPortModeByPortName(startElementPortMtnEvth.getTerminalName());

            ElementPortMtnEvth endElementPortMtnEvth = elementPortMtnEvthMapper.selectElementPortMtnEvthById(elementBusiMtnChannelVeth.getEndElementVethId());
            ElementPortMode endElementPortMode = elementPortModeMapper.selectElementPortModeByPortName(endElementPortMtnEvth.getTerminalName());

            linkResult = netElementLinkMapper.deleteNetElementLinkByParams(startElementPortMode.getId(), endElementPortMode.getId());
            elementPortModeMapper.deleteElementPortModeById(startElementPortMode.getId());
            elementPortModeMapper.deleteElementPortModeById(endElementPortMode.getId());
        }
        return linkResult;
    }

    /**
     * @param subLines
     * @return
     */
    public List<List<NetElementLinkVo>> combine(List<List<NetElementLinkVo>> subLines) {
        List<List<NetElementLinkVo>> result = new ArrayList<>();
        if (subLines == null || subLines.isEmpty()) {
            return result;
        }
        backtrack(subLines, 0, new ArrayList<>(), result);
        return result;
    }

    private void backtrack(List<List<NetElementLinkVo>> subLines, int index, List<NetElementLinkVo> currentCombination, List<List<NetElementLinkVo>> result) {
        if (index == subLines.size()) {
            result.add(new ArrayList<>(currentCombination));
            return;
        }
        List<NetElementLinkVo> currentList = subLines.get(index);
        for (NetElementLinkVo element : currentList) {
            currentCombination.add(element);
            backtrack(subLines, index + 1, currentCombination, result);
            currentCombination.remove(currentCombination.size() - 1);
        }
    }
}
